package com.mes.utils;

import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;
import com.yy.base.util.SystemProperties;

public class ConnectionUtil {
	private static String jdbcDriver = null; // 数据库驱动
	private static String url = null; // 数据 URL
	private static String userName = null; // 数据库用户名
	private static String password = null; // 数据库用户密码
	private static String testSql = null; // 测试连接是否可用的测试表名，默认没有测试表
	private static Vector<ConnectionInfo> connectionlist = null;
	private static Map<Connection, ConnectionInfo> connectionMap = null;
	private static int initCount = 3;
	private static int addCount = 3;
	private static int maxCount = 20;

	/**
	 * 获取数据库连接
	 */
	public synchronized static Connection getConnection() {
		if (jdbcDriver == null) {
			createPool();
		}
		Connection connection = null;
		do {
			connection = getFreeConnection();
		} while (connectionlist == null);
		//当连接池数量不够时创建新连接
		if (connection == null) {
			createConnection(addCount);
			connection = getFreeConnection();
		}
		long time = System.currentTimeMillis();
		//当连接超过最大数量时等待连接归还
		if (connection == null) {
			while (true) {
				connection = getFreeConnection();
				if (connection != null) {
					break;
				}
				if ((System.currentTimeMillis() - time) / 1000 > 5) {
					throw new RuntimeException("等待连接池建立连接超时，请重试！");
				}
			}
		}
		return connection;
	}
	
	/**
	 * 创建数据库连接池
	 */
	private static void createPool() {
		jdbcDriver = SystemProperties.getValue("jdbc.driverClassName");
		url = SystemProperties.getValue("jdbc.url");
		userName = SystemProperties.getValue("jdbc.username");
		password = SystemProperties.getValue("jdbc.password");
		testSql = SystemProperties.getValue("jdbc.testSql");
		
		String init = SystemProperties.getValue("jdbc.initCount");
		if (init != null) {
			initCount = Integer.parseInt(init);
		}
		String add = SystemProperties.getValue("jdbc.addCount");
		if (add != null) {
			addCount = Integer.parseInt(add);
		}
		String max = SystemProperties.getValue("jdbc.maxCount");
		if (max != null) {
			maxCount = Integer.parseInt(max);
		}
		
		if (connectionlist == null) {
			connectionlist = new Vector<ConnectionInfo>();
			connectionMap = new HashMap<Connection, ConnectionInfo>();
		}
		try {
			Driver driver = (Driver) (Class.forName(jdbcDriver).newInstance());
			DriverManager.registerDriver(driver); // 注册 JDBC 驱动程序
		} catch (Exception e) {
			throw new RuntimeException("注册JDBC驱动程序异常：" + e.getMessage());
		}
		createConnection(initCount);
	}
	
	/**
	 * 销毁原有连接，建立新连接池
	 * @param prop
	 */
	public static void initPool() {
		if (connectionlist != null) {
			for (ConnectionInfo conn : connectionlist) {
				try {
					conn.getConnection().close();
				} catch (Exception e) {
				}
			}
			connectionlist.clear();
			connectionMap.clear();
		}
		createPool();
	}
	
	private static void createConnection(int count) {
		int size = connectionlist.size();
		if (size < maxCount) {
			int max = size + count < maxCount ? size + count : maxCount;
			ConnectionInfo conn = null;
			Connection connection = null;
			for (;size < max; size ++) {
				conn = new ConnectionInfo();
				connection = createConnection();
				conn.setConnection(connection);
				conn.setStatus("FREE");
				connectionlist.add(conn);
				connectionMap.put(connection, conn);
			}
		}
		System.out.println("已建立连接数：" + connectionlist.size());
	}
	
	private static Connection getFreeConnection() {
		int size = connectionlist.size();
		ConnectionInfo conn = null;
		for (int i = 0; i < size; i++) {
			conn = connectionlist.get(i);
			try {
				if (conn.getConnection().isClosed()) {
					connectionMap.remove(conn.getConnection());
					connectionlist.remove(conn);
					size --;
					i --;
					continue;
				}
			} catch (Exception e) {
				continue;
			}
			if ("FREE".equals(conn.getStatus())) {
				Connection connection = conn.getConnection();
				if (!testConnection(connection)) {
					connectionMap.remove(conn.getConnection());
					connectionlist.remove(conn);
					size --;
					i --;
					continue;
				}
				conn.setStatus("USE");
				return connection;
			}
		}
		return null;
	}
	
	private static boolean testConnection(Connection connection) {
		if (testSql != null && !"".equals(testSql)) {
			PreparedStatement ps = null;
			try {
				ps = connection.prepareStatement(testSql);
				ps.executeQuery();
			} catch (Exception e) {
				return false;
			} finally {
				try {
					ps.close();
				} catch (Exception e) {
				}
			}
		}
		return true;
	}
	
	private static Connection createConnection() {
		try {
			return DriverManager.getConnection(url, userName, password);
		} catch (Exception e) {
			throw new RuntimeException("创建数据库连接异常：" + e.getMessage());
		}
	}
	
	public static void resetConnection(Connection connection) {
		ConnectionInfo connectionInfo = connectionMap.get(connection);
		if (connectionInfo != null) {
			if ("CLOSE".equals(connectionInfo.getStatus())) {
				connectionMap.remove(connection);
				connectionlist.remove(connectionInfo);
			} else {
				try {
					if (connection.isClosed()) {
						connectionMap.remove(connection);
						connectionlist.remove(connectionInfo);
					}
				} catch (Exception e) {
				}
				try {
					if (!connection.getAutoCommit()) {
						connection.setAutoCommit(true);
					}
				} catch (Exception e) {
				}
				connectionInfo.setStatus("FREE");
				return;
			}
		}
		try {
			connection.close();
		} catch (Exception e) {
		}
	}
	
	public void clearPool() {
		int size = connectionlist.size();
		ConnectionInfo conn = null;
		for (int i = 0; i < size; i++) {
			conn = connectionlist.get(i);
			try {
				if ("FREE".equals(conn.getStatus())) {
					if (!conn.getConnection().isClosed()) {
						conn.getConnection().close();
					}
					connectionMap.remove(conn.getConnection());
					connectionlist.remove(conn);
					size --;
					i --;
					continue;
				}
			} catch (Exception e) {
				continue;
			}
			conn.setStatus("CLOSE");
		}
	}
	
	public String getJdbcDriver() {
		return jdbcDriver;
	}
	public String getUrl() {
		return url;
	}
	public String getUserName() {
		return userName;
	}
	public String getPassword() {
		return password;
	}
	public String getTestSql() {
		return testSql;
	}
}